﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Globalization;
using System.Windows.Forms;
using GeoRef;
using TripLoaGeoCodingApp.Properties;
using System.Xml;

namespace TripLoaGeoCodingApp
{
    public partial class GeoCodingForm : Form
    {
        /// <value>
        /// Object which provides geocoding info
        /// </value>
        GeoQuery q;
        
        /// <value>
        /// Location which identifies required
        /// geographical information
        /// </value>
        List<GeoLoc> loc;

        /// <value>
        /// Url where map is contained. This map
        /// represents required place
        /// </value>
        string url;

        /// <value>
        /// Zoom level to represent searched location
        /// </value>
        string zoomLev;

        /// <summary>
        /// Initializes GeoQuery object, map image,
        /// useful textBox to insert geographical
        /// information
        /// </summary>
        public GeoCodingForm() {
            InitializeComponent();
            q = new GeoQuery();
            this.DefaultStateText();
            loc = new List<GeoLoc>();
            map.WaitOnLoad = false;            
        }

        /// <summary>
        ///  Retrieves coordinates about request
        ///  and draw associated map, if it is possible,
        ///  otherwise shows an alert
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ok_Click(object sender, EventArgs e) {
            List<string> param = new List<string>();
            zoomLev = "12";//zoom level of nation
            loc.Clear();
            try {
                //Controls textBox content, adds its values to quey parameters
                if (stateText.Text.Length != 0) {
                    param.Add(stateText.Text);                    
                } else {
                    param.Add(null);
                }
                if (cityText.Text.Length != 0) {
                    param.Add(cityText.Text);
                    zoomLev = "6"; //zoom level of city
                } else {
                    param.Add(null);
                }
                if (zpText.Text.Length != 0) {
                    param.Add(zpText.Text);
                    zoomLev = "4"; //zoom level about zip code
                } else {
                    param.Add(null);
                }
                if (addrText.Text.Length != 0) {
                    param.Add(addrText.Text);
                    zoomLev = "1"; //zoom level about address
                } else {
                    param.Add(null);
                }
                if (totAddrText.Text.Length != 0) {
                    param.Add(totAddrText.Text);
                    zoomLev = "6";
                } else {
                    param.Add(null);
                }
                
                if (param.ElementAt(4) == null) {
                    loc.AddRange(q.geoCoding(param.ElementAt(0), param.ElementAt(1), param.ElementAt(2), param.ElementAt(3)));
                } else {
                    loc.AddRange(q.geoCoding(param.ElementAt(4)));
                }
                listLocation.Items.Clear();
                listLocation.Refresh();
                listLocation.BeginUpdate();
                foreach (GeoLoc l in loc) {
                    listLocation.Items.Add(l.Address);
                }
                listLocation.EndUpdate();
                listLocation.SetSelected(0, true);

                
            } catch (GeoRef.Exceptions.GeoCodingException) {
                MessageBox.Show("Sorry, service is not available\n or data don't represent a\n correct format");
            }
            ClearCommands();            
        }
        
        /// <summary>
        /// Clears all textBox of geographical information,
        /// disables buttons and hides map
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void cancel_Click(object sender, EventArgs e) {
            stateText.Clear();
            zpText.Clear();
            cityText.Clear();
            addrText.Clear();
            totAddrText.Clear();
            ClearCommands();            
            coordGeoPoint.Visible = false;
            coord.Visible = false;                        
            map.Visible = false;            
        }       

        /// <summary>
        /// If possible draws map about geographical
        /// information, otherwise shows another
        /// image
        /// </summary>
        private void DrawMap() {
            XmlReader xml;            
            
            try {
                //Retrieve xml file from specified url and load it
                xml = XmlReader.Create(url);               
                XmlDocument doc = new XmlDocument();
                doc.Load(xml);
                map.Visible = true;
                /*Checks if xml content is valid geographical data,
                 * and retrieves url of map image*/
                if (doc.DocumentElement.Name == "Result") {                    
                    map.ImageLocation = doc.DocumentElement.InnerText;                    
                } else { //otherwise shows prohibition image     
                    map.ImageLocation = "http://eyeonweb.net/wp-content/uploads/divieto.jpg";
                }                
                //Load asynchronously image
                map.LoadAsync();
                
            } catch{
                return;
            }
        }

        /// <summary>
        /// Checks if state textBox is filled, then enabled
        /// ok and cancel buttons, otherwise doesn't allow to
        /// continue geocoding
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void stateText_TextChanged(object sender, EventArgs e) {
            totAddrText.Enabled = false;
            if (stateText.Text.Length > 0) {
                zpText.Enabled = true;
                cancel.Enabled = true;
                
            } else {
                ok.Enabled = false;
                zpText.Enabled = false;
                cityText.Enabled = false;
                addrText.Enabled = false;
            }
            zpText.Enabled = true;
            cityText.Enabled = true;
        }

        /// <summary>
        /// Enables address textBox
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void cityText_TextChanged(object sender, EventArgs e) {
            addrText.Enabled = true;
            if ( zpText.Text.Length == 0 && cityText.Text.Length != 0) {
                ok.Enabled = true;
            }
        }

        /// <summary>
        /// If zpText textBox is filled enables
        /// city textBox
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void zpText_TextChanged(object sender, EventArgs e) {
            if (zpText.Text.Length > 0) {
                cityText.Enabled = true;
            }
        }

        /// <summary>
        /// If address is filled, ok button is enabled
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void addrText_TextChanged(object sender, EventArgs e) {
            if (zpText.Text.Length != 0) {
                ok.Enabled = true;
            }
        }
        /// <summary>
        /// Disable other input fields, if this is filled, then
        /// enable ok button
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void totAddrText_TextChanged(object sender, EventArgs e) {
            stateText.Enabled = false;
            cityText.Enabled = false;
            zpText.Enabled = false;
            addrText.Enabled = false;
            if (totAddrText.Text.Length != 0) {
                ok.Enabled = true;
            }
        }

        /// <summary>
        /// Clears map images and restores
        /// initial status of textBoxes and
        /// buttons
        /// </summary>
        private void ClearCommands(){
            this.DefaultStateText();            
            map.Image = null;
            map.Invalidate();                     
        }

        /// <summary>
        /// Disables all textBoxes for geographical informations,
        /// except for state one, and buttons. Creates a base url
        /// to retrieve next coordinates
        /// </summary>
        private void DefaultStateText() {
            this.ResetUrl();            
            zpText.Enabled = false;
            addrText.Enabled = false;
            cityText.Enabled = false;
            totAddrText.Enabled = true;
            stateText.Enabled = true;
            ok.Enabled = false;
            cancel.Enabled = false;
        }

        /// <summary>
        /// Composes again an url address
        /// </summary>
        private void ResetUrl() {
            url = Settings.Default.yahooMapImg + ("?appid=") + Settings.Default.yahooAppID;
            url += ("&image_width=") + map.Width + ("&image_height=") + map.Height;
        }

        /// <summary>
        /// Changes url when listbox item is changes and so 
        /// update coordinates and shown map
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void listLocation_SelectedIndexChanged(object sender, EventArgs e) {
            //Composes url of required information of latitude, longitude and zoom level
            ResetUrl();
            url += ("&latitude=") + string.Format(CultureInfo.InvariantCulture, "{0:G}", loc.ElementAt(listLocation.SelectedIndex).Lat) + ("&longitude=") + string.Format(CultureInfo.InvariantCulture, "{0:G}", loc.ElementAt(listLocation.SelectedIndex).Lng);
            url += ("&zoom=") + zoomLev;
            //Shows coordinates in TextBox
            coordGeoPoint.Visible = true;
            coord.Visible = true;
            coordGeoPoint.Text = loc.ElementAt(listLocation.SelectedIndex).ToString();
            DrawMap();
        }


        


    }
}
